#include "zdc.h"

ZNode::ZNode(ZDal& dal)
:m_dal(dal)
{
	m_user.init(m_dal.m_env);
	m_node.init(m_dal.m_env);
	m_lasterr.init(m_dal.m_env);
}

ZNode::ZNode( ZDal& dal, const char* node)
:m_dal(dal)
{
	m_user.init(m_dal.m_env);
	m_node.init(m_dal.m_env);
	m_lasterr.init(m_dal.m_env);
	AttachNode(node);
}

#define __ZDC_CHKATNODE if (!m_node.isTable()){m_lasterr.setString("not attach a node"); return -1;}
int ZNode::AttachNode(const char* nid)
{
	zString sr;
	int re;
	zLuaObj getnode(m_dal.m_app,"GetNode");	
	zLuaObj getnode2(m_dal.m_app,"SureNode");
	re=getnode.call_va_err(&sr,zlua_traceback,"Os>OO",&m_dal.m_app,nid,&m_node,&m_lasterr);
	if (re>=0)
	{
		if (!m_node.isTable())
		{
			re=-1;
		}
		ZCHKDBG(NULL,"AttachNode(%s)=[%s,%s]",nid,m_node.getField("__id").getString(),m_lasterr.getString());
	}
	else
	{
		m_lasterr.setString(sr);
		m_node.SetNil();
		ZCHKDBG(NULL,"AttachNode(%s)=[%s,%s]",nid,m_node.getField("__id").getString(),m_lasterr.getString());
	}
	if (!m_node.isTable())
	{
		re=-1;
	}
	return re;
}
bool ZNode::IsAttached() const
{
	return m_node.isTable();
}

int ZNode::Call(const char* fun,zVar* args,zVar* r1,zVar* r2n)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re;
	zString sr;

	re=m_dal.m_api_callact.call_va_err(&sr,zlua_traceback,"OOOsV>bAV",&m_user,&m_dal.m_app,&m_node,fun,args,&br,r1,r2n);
	if (re>=0)
	{
		if (!br)
		{
			re=-1;
		}		
		ZCHKDBG(NULL,"Call(%s.%s,%s)=[%d,%s]%s,%s",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,r1?r1->toString().c_str():"?",r2n?r2n->toString().c_str():"?");
	}
	else
	{
		m_lasterr.setString(sr);
		ZCHKDBG(NULL,"Call(%s.%s,%s)=%d,%s",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,sr.c_str());
	}
	return re;
}
int ZNode::aCall(const char* fun,zVar* args)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re;
	zString sr;
	re=m_dal.m_api_asynccall.call_va_err(&sr,zlua_traceback,"OOOOsV>bO",&m_user,&m_dal.m_app,NULL,&m_node,fun,args,&br,&m_lasterr);
	if (re>=0)
	{
		if (!br)
		{
			re=-1;
		}		
		ZCHKDBG(NULL,"aCall(%s.%s,%s)=[%d,%s]",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,m_lasterr.getString());
	}
	else
	{
		m_lasterr.setString(sr);
		ZCHKDBG(NULL,"aCall(%s.%s,%s)=%d,%s",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,sr.c_str());
	}
	return re;
}
static int acall_cb (lua_State *L)
{
	ZACALL_CB cb =(ZACALL_CB) lua_touserdata(L, lua_upvalueindex(1));
	void* userp1 = lua_touserdata(L, lua_upvalueindex(2));
	void* userp2 = lua_touserdata(L, lua_upvalueindex(3));
	int err = lua_tointeger(L,1);
	zVar r1,r2n;
	zVarFromLua(L,r1,2);
	zVarFromLuaVa(L,r2n,3,200);

	int r=cb(userp1,userp2,err,r1,r2n);
	lua_pushinteger(L,r);
	return 1;
}
int ZNode::aCallCB(ZACALL_CB cb,void* userp1,void* userp2,const char* fun,zVar* args)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re;
	zString sr;
	if (cb)
	{
		lua_pushlightuserdata(m_dal.m_env,(void*)cb);
		lua_pushlightuserdata(m_dal.m_env,userp1);
		lua_pushlightuserdata(m_dal.m_env,userp2);
		lua_pushcclosure(m_dal.m_env, acall_cb,3);
		zLuaObj ccb(m_dal.m_env,true);
		re=m_dal.m_api_asynccall.call_va_err(&sr,zlua_traceback,"OOOOsV>bO",&m_user,&m_dal.m_app,&ccb,&m_node,fun,args,&br,&m_lasterr);
	}
	else
	{
		re=m_dal.m_api_asynccall.call_va_err(&sr,zlua_traceback,"OOOOsV>bO",&m_user,&m_dal.m_app,NULL,&m_node,fun,args,&br,&m_lasterr);
	}	
	if (re>=0)
	{
		if (!br)
		{
			re=-1;
		}		
		ZCHKDBG(NULL,"aCall(%s.%s,%s)=[%d,%s]",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,m_lasterr.getString());
	}
	else
	{
		m_lasterr.setString(sr);
		ZCHKDBG(NULL,"aCall(%s.%s,%s)=%d,%s",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,sr.c_str());
	}
	return re;
}
static int acallobj_cb (lua_State *L)
{
	ZACALLOBJ* cb =*(ZACALLOBJ**) lua_touserdata(L, lua_upvalueindex(1));
	int err = lua_tointeger(L,1);
	zVar r1,r2n;
	zVarFromLua(L,r1,2);
	zVarFromLuaVa(L,r2n,3,200);

	int r=cb->cb(err,r1,r2n);
	lua_pushinteger(L,r);
	return 1;
}
int ZNode::aCallCB(ZACALLOBJ* cb,const char* fun,zVar* args)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re;
	zString sr;
	ZACALLOBJ **ppcb = (ZACALLOBJ **)lua_newuserdata(m_dal.m_env, sizeof(ZACALLOBJ*));
	*ppcb=cb;
	lua_pushcclosure(m_dal.m_env, acallobj_cb,1);
	zLuaObj ccb(m_dal.m_env,true);
	re=m_dal.m_api_asynccall.call_va_err(&sr,zlua_traceback,"OOOOsV>bO",&m_user,&m_dal.m_app,&ccb,&m_node,fun,args,&br,&m_lasterr);
	if (re>=0)
	{
		if (!br)
		{
			re=-1;
		}		
		ZCHKDBG(NULL,"aCall(%s.%s,%s)=[%d,%s]",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,m_lasterr.getString());
	}
	else
	{
		m_lasterr.setString(sr);
		ZCHKDBG(NULL,"aCall(%s.%s,%s)=%d,%s",m_node.getField("__id").getString(),fun,args?args->toString().c_str():"nil",re,sr.c_str());
	}
	return re;
}
int ZNode::Set(zVar* attr,zVar* pv)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re=-1;
	zString sr;
	if (!attr || !pv)
	{
		ZCHKDBG(NULL,"Set(?,?)=-1,bad arg type");
		sr="EBAT1:Nil";
		return re;
	}
	re = m_dal.m_api_set.call_va_err(&sr,zlua_traceback,"OOOAA>bO",&m_user,&m_dal.m_app,&m_node,attr,pv,&br,&m_lasterr);
	
	if (re>=0)
	{
		if (!br)
		{
			// log error
			ZCHKDBG(NULL,"Set(%s,%s)=-1,%s",attr->toString().c_str(),pv->toString().c_str(),m_lasterr.getString());
			return -1;
		}
		ZCHKDBG(NULL,"Set(%s,%s)=0",attr->toString().c_str(),pv->toString().c_str());
		return 0;
	}
	m_lasterr.setString(sr);
	ZCHKDBG(NULL,"Set(%s,%s)=%d,%s",attr->toString().c_str(),pv->toString().c_str(),re,sr.c_str());
	return re;
}
int ZNode::UnSet(zVar* attr)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re=-1;
	zString sr;
	if (!attr)
	{
		ZCHKDBG(NULL,"UnSet(?)=-1,bad arg type");
		sr="EBAT1:Nil";
		return re;
	}
	re = m_dal.m_api_unset.call_va_err(&sr,zlua_traceback,"OOOA>bO",&m_user,&m_dal.m_app,&m_node,attr,&br,&m_lasterr);

	if (re>=0)
	{
		if (!br)
		{
			// log error
			ZCHKDBG(NULL,"UnSet(%s)=-1,%s",attr->toString().c_str(),m_lasterr.getString());
			return -1;
		}
		ZCHKDBG(NULL,"UnSet(%s)=0",attr->toString().c_str());
		return 0;
	}
	m_lasterr.setString(sr);
	ZCHKDBG(NULL,"UnSet(%s)=%d,%s",attr->toString().c_str(),re,sr.c_str());
	return re;
}
int ZNode::UpdateSub(const char* subnode,zVar* pv)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re=-1;
	zString sr;
	if (!subnode || !pv)
	{
		ZCHKDBG(NULL,"UpdateSub(?,?)=-1,bad arg type");
		sr="EBAT1:Nil";
		return re;
	}
	re = m_dal.m_api_updatesub.call_va_err(&sr,zlua_traceback,"OOOsA>bO",&m_user,&m_dal.m_app,&m_node,subnode,pv,&br,&m_lasterr);

	if (re>=0)
	{
		if (!br)
		{
			// log error
			ZCHKDBG(NULL,"UpdateSub(%s,%s)=-1,%s",subnode,pv->toString().c_str(),m_lasterr.getString());
			return -1;
		}
		ZCHKDBG(NULL,"UpdateSub(%s,%s)=0",subnode,pv->toString().c_str());
		return 0;
	}
	m_lasterr.setString(sr);
	ZCHKDBG(NULL,"UpdateSub(%s,%s)=%d,%s",subnode,pv->toString().c_str(),re,sr.c_str());
	return re;
}

int ZNode::CreateSub(const char* sub,zVar* mc)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re=-1;
	zString sr;
	if (!sub)
	{
		ZCHKDBG(NULL,"CreateSub(?,_)=-1,bad arg type");
		sr="EBAT1:Nil";
		return re;
	}
	re = m_dal.m_api_createsub.call_va_err(&sr,zlua_traceback,"OOOsA>bO",&m_user,&m_dal.m_app,&m_node,sub,mc,&br,&m_lasterr);

	if (re>=0)
	{
		if (!br)
		{
			// log error
			ZCHKDBG(NULL,"CreateSub(%s,%s)=-1,%s",sub,mc?mc->toString().c_str():"Nil",m_lasterr.getString());
			return -1;
		}
		ZCHKDBG(NULL,"CreateSub(%s,%s)=0",sub,mc?mc->toString().c_str():"Nil");
		return 0;
	}
	m_lasterr.setString(sr);
	ZCHKDBG(NULL,"CreateSub(%s,%s)=%d,%s",sub,mc?mc->toString().c_str():"Nil",re,sr.c_str());
	return re;
}
int ZNode::DeleteSub(const zVar* sub)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int br;
	int re=-1;
	zString sr;
	if (!sub)
	{
		ZCHKDBG(NULL,"DeleteSub(?)=-1,bad arg type");
		sr="EBAT1:Nil";
		return re;
	}
	re = m_dal.m_api_deletesub.call_va_err(&sr,zlua_traceback,"OOOA>bO",&m_user,&m_dal.m_app,&m_node,sub,&br,&m_lasterr);

	if (re>=0)
	{
		if (!br)
		{
			// log error
			ZCHKDBG(NULL,"DeleteSub(%s)=-1,%s",sub->toString().c_str(),m_lasterr.getString());
			return -1;
		}
		ZCHKDBG(NULL,"DeleteSub(%s)=0",sub->toString().c_str());
		return 0;
	}
	m_lasterr.setString(sr);
	ZCHKDBG(NULL,"DeleteSub(%s)=%d,%s",sub,re,sr.c_str());
	return re;
}

int ZNode::FetchSub(const zVar* tmpl,int lvl, zVar* r1)
{
	__ZDC_CHKATNODE;
	ClearLastErr();
	int re=-1;
	zString sr;
	re = m_dal.m_api_fetch_node.call_va_err(&sr,zlua_traceback,"OOOAi>A",&m_user,&m_dal.m_app,&m_node,tmpl,lvl,r1);

	if (re>=0)
	{
		ZCHKDBG(NULL,"FetchSub(%s,%d)=0",tmpl?tmpl->toString().c_str():"Nil",lvl);
		return 0;
	}
	m_lasterr.setString(sr);
	ZCHKDBG(NULL,"FetchSub(%s,%d)=%d,%s",tmpl?tmpl->toString().c_str():"Nil",lvl,re,sr.c_str());
	return re;
}

ZDal::ZDal(ZLuaEnv& env)
:m_env(env)
{

}
int ZDal::Init()
{
	int re=m_env.dolibrary("zdc.nodeapi");
	zLuaObj zdc(m_env,"zdc");
	zLuaObj nodeapi(zdc,"nodeapi");
	m_app.init(m_env);
	m_api_callact.linkTo(nodeapi,"callact");
	m_api_asynccall.linkTo(nodeapi,"asynccall");
	m_api_set.linkTo(nodeapi,"set");
	m_api_unset.linkTo(nodeapi,"unset");
	m_api_updatesub.linkTo(nodeapi,"updatesub");
	m_api_createsub.linkTo(nodeapi,"createsub");
	m_api_deletesub.linkTo(nodeapi,"mdelsub");
	m_api_fetch_node.linkTo(nodeapi,"fetch_node");
	return re;
}

int ZDal::AttachDal(const char* GlobalName)
{
	m_app.linkTo(m_env,GlobalName);
	if (m_app.isluafalse())
		return -1;
	return 0;
}
